using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Threading;

using Dashboard.Util;

namespace Dashboard
{
	internal abstract class XmlConnectionHandler
	{
		private static ThreadPond thread_pond = null;

		private Thread thread = null;
		private object client_lock = new object ();

		public event EventHandler Canceled;

		static XmlConnectionHandler ()
		{
			thread_pond = new ThreadPond (10);
			thread_pond.Start ();
		}

		public XmlConnectionHandler ()
		{
		}

		public void Start ()
		{
			// FIXME: Right now we spawn the handler into a new 
			// thread, it might be nice to use the thread-pool 
			// here. However, the current one is pretty ghetto 
			// and can't grow.

			thread = new Thread (new ThreadStart (Worker));
			thread.Start ();			
		}

		public abstract void Close ();
		
		private void Worker ()
		{
			// Read the data off the socket and store it in a
			// temporary memory buffer.  Once the end-of-message
			// character has been read, discard remaining data
			// and deserialize the request.
			
			byte[] network_data = new byte [4096];
			MemoryStream buffer_stream = new MemoryStream ();
			int bytes_read, total_bytes = 0, end_index = -1;
			
			do {
				bytes_read = 0;
				
				try {
					lock (client_lock) {
						// The connection may have been closed within this loop.
						if (!Closed)
							bytes_read = Stream.Read (network_data, 0, 4096);
					}
				} catch (Exception e) {
					// Aborting the thread mid-read will
					// cause an IOException to be thorwn,
					// which sets the ThreadAbortException
					// as its InnerException.
					
					if (!(e is IOException || e is ThreadAbortException))
						throw;
					
					return;
				}
				
				total_bytes += bytes_read;
				
				if (bytes_read > 0) {
					// 0xff signifies end of message
					end_index = ArrayFu.IndexOfByte (network_data, (byte) 0xff);
					buffer_stream.Write (network_data, 0, end_index == -1 ? bytes_read : end_index);
				}
			} while (bytes_read > 0 && end_index == -1);
			
			// Something just connected to our socket and then
			// hung up.  It's no big deal, so just clean up and 
			// close without running any handlers.
			
			if (total_bytes == 0)
				return;
			
			buffer_stream.Seek (0, SeekOrigin.Begin);
			
			//Message message = null;
			//
			//try {
			//	message = Message.Serializer.Deserialize (buffer_stream) as Message;
			//} catch (Exception e) {
			//	Console.WriteLine ("Failed to deserialize message");
			//	Console.WriteLine (e);
			//}
		}
		
		protected abstract Stream Stream {
			get;
		}
		
		protected abstract bool Closed {
			get;
		}
	}
}
